﻿using System;
using System.Collections.Generic;
using System.Text;
using Vortex.SceneFramework;
using Vortex.Drawing;
using Vortex.Resources;

namespace Vortex.Demo.Pacman {

	///<summary>Lost life callback</summary>
	public delegate void LostLifeCallbackHandler(int lifesLeft);

	///<summary>Implementation of Pacman GameWorld</summary>
	class GameWorld : Node, ISceneComponent {		
		[SceneComponent]
		private WorldAssets _assets = new WorldAssets();

		[ElementRef]
		public PacmanUnit PacmanUnit { get; private set; }
		[ElementRef] private TextElement ScoreText = null;
		[ElementRef] private TextElement LivesText = null;

		private WorldMap _map = new WorldMap();

		///<summary>Information about current level info</summary>
		private LevelInfo _currentLevelInfo;

		///<summary>Number of ghost kills after big point was eatten</summary>
		private int _hitCount = 0;

		/// <summary>
		/// Gets the map of this world.
		/// </summary>
		/// <value>The map of this world.</value>
		public WorldMap Map { 
			get { return _map; }
		}

		#region World Update Methods

		public override void Update(float timeDelta) {
			//update content layout: location of world, other labels etc
			UpdateContentLayout();			
			//then update label text or so
			UpdateContentText();

			if (IsEnabled) {
				//check unit interaction
				CheckUnitInteraction();
			}
		}

		/// <summary>
		/// Checks the unit interaction. Interating all of ghosts and comparing distance with threshold.
		/// </summary>
		private void CheckUnitInteraction() {
			foreach (GhostUnit ghost in GetChildren<GhostUnit>()) {
				if (ghost.Location.Distance(PacmanUnit.Location) < Constants.UNIT_INTERACTION_DISTANCE) {
					if (ghost.State == GhostState.Hunting) {
						KillPacman();
					} else if (ghost.State == GhostState.Escaping) {						
						EatGhost(ghost);
					}
				}
			}
		}

		/// <summary>
		/// Updates the labels' text.
		/// </summary>
		private void UpdateContentText() {
			ScoreText.Text = string.Format("Score: {0:000000}", PacmanUnit.Score);
			LivesText.Text = string.Format("Lifes: {0}", PacmanUnit.Lifes);
		}

		/// <summary>
		/// Updates the layout of content.
		/// </summary>
		private void UpdateContentLayout() {
			float bottomStatusHeight = _assets.MiddleFont.LineHeight * 0.65f;
			float bottomStatusHeightCorrection = bottomStatusHeight * 0.35f;
			Vector2 mapSize = new Vector2(_map.Width, _map.Height) * Scale;
			//first and most important, align world in screen space, pacman world always be in center
			Location = (PacmanGame.SCREEN_SIZE.Half - (mapSize + new Vector2(0, bottomStatusHeight)).Half).Floored;
			//locate other elements
			ScoreText.Location = new Vector2(LocationX, LocationY + mapSize.Y - bottomStatusHeightCorrection);
			LivesText.Location = new Vector2(LocationX + mapSize.X - Scale.X, LocationY + mapSize.Y - bottomStatusHeightCorrection);
		}

		#endregion

		protected override void Draw(Canvas2D canvas) {
			//draw canvas
			RenderMap(canvas, _map);
		}

		#region ISceneComponent Members

		/// <summary>
		/// Invoked on game world component is loaded.
		/// </summary>
		/// <param name="resources">The domain resource collection.</param>
		public void ComponentLoad(IResourceCollection resources) {
			PacmanUnit.BigPointEated += new CallbackHandler(EnforcePacman);
		}

		/// <summary>
		/// Invoked on game world component is unloaded.
		/// </summary>
		public void ComponentUnload() {
			;	
		}

		#endregion

		private void EnforcePacman() {
			//reset hit count
			_hitCount = 0;
			//scare each of ghosts
			foreach (GhostUnit ghost in GetChildren<GhostUnit>()) {
				if (ghost.State != GhostState.Returning) {
					ghost.Scare(Constants.GHOST_ESCAPE_TIME_BASE);
				}
			}
		}

		private void RenderMap(Canvas2D canvas, WorldMap worldMap) {
			ColorU wallsColor = new ColorU(0xFF0000F0);

			int width = worldMap.Width, height = worldMap.Height;
			float superDotPulse = (PacmanGame.Time.TotalGameTime * 2.0f) % 1.0f * 0.5f;

			for (int n = 0; n < height; ++n) {
				for (int m = 0; m < width; ++m) {
					Vector2 cellPoint = new Vector2(m, n);
					WorldMapItem item = worldMap[m, n];
					switch (item.type) {
						case MapItemType.Dot:
							canvas.DrawSprite(cellPoint, Vector2.Unit, _assets.DotsTiles[0], ColorU.Blank);
							break;
						case MapItemType.SuperDot:
							canvas.DrawSprite(cellPoint, Vector2.Unit * (1.0f + superDotPulse), superDotPulse, _assets.DotsTiles[1], ColorU.Blank.MultiplyAlpha(0.75f));
							canvas.DrawSprite(cellPoint, Vector2.Unit, _assets.DotsTiles[1], ColorU.Blank);
							break;
						case MapItemType.Wall:
							if (item.index > 0) {
								canvas.DrawSprite(cellPoint, Vector2.Unit, _assets.WallTiles[item.index], wallsColor);
							}
							break;
					}
				}
			}
		}

		#region Manage world state

		/// <summary>
		/// Kills the pacman.
		/// </summary>
		private void KillPacman() {
			PacmanUnit.Kill();
		}

		private void EatGhost(GhostUnit ghost) {
			//kill ghost first
			ghost.Kill();
			//choose score from hit table
			int score = Constants.HIT_SCORES[_hitCount++];
			PacmanUnit.Score += score;
			
		}

		/// <summary>
		/// Starts the level fir this world.
		/// </summary>
		/// <param name="levelNumber">The level number.</param>
		public void StartLevel(int levelNumber) {
			_currentLevelInfo = new LevelInfo(levelNumber);
			_map.Fill(_currentLevelInfo.Map);

			ResetLevel();
		}

		/// <summary>
		/// Resets the level but do not refill map.
		/// </summary>
		public void ResetLevel() {
			PacmanUnit.Initialize(_currentLevelInfo.PlayerStartPosition, Vector2.Left);

			int index = 0;
			foreach (GhostUnit ghost in GetChildren<GhostUnit>()) {
				ghost.Initialize(_currentLevelInfo.GhostStartPositions[index], index * 2);
				index++;
			}
		}

		#endregion
	}
}